/******************************************************************************
//             INTEL CORPORATION PROPRIETARY INFORMATION
//  This software is supplied under the terms of a license agreement or
//  nondisclosure agreement with Intel Corporation and may not be copied
//  or disclosed except in accordance with the terms of that agreement.
//        Copyright (c) 2000-2001 Intel Corporation. All Rights Reserved.
//
//  Description:
//      Intel(R) JPEG library for X platform 
//
********************************************************************************/
#include "_ijx.h"


/******************************************************************************
// Name:            ijxCompressInit
// Description:     Init function for encoding.
// Input Arguments:
//        nQuality: Indicates quality of compressed image.
// nResartInterval: Indicates the number of resart interval.
//   nJPEGCodeMode: Indicates JPEG compress mode.
//      pImageSpec: Points to IIPIMAGESPEC data structure.
//       pWaveSpec: Points to IWPWAVESPEC data structure.
//     pMotionSpec: Points to IJMOTIONSPEC data structure.
//         pStream: Identifies IJBITTREAMSTATE data structure.
// Output Arguments:
//    pEncodeState: Identifies IJENCODESTATE strcuture.
//                          
// Returns:          
//        [Success] IJX_RTCODE_OK
//        [Failure] IJX_RTCODE_BAGARG
//                  IJX_RTCODE_INSUFFICIENTBUF
//                  IJX_RTCODE_NOTSUPPORTMARKER
//                  IJX_RTCODE_ERRPARSE
//                  IJX_RTCODE_E_NOTSUPPORTEDPARAM   
//                  
******************************************************************************/
IJXRESULT ijxCompressInit (int nQuality,
                           int nResartInterval,
                           int nJPEGCodeMode,
                           const IIPIMAGESPEC *pImageSpec,
                           const IWPWAVESPEC  *pWaveSpec,
                           const IJMOTIONSPEC *pMotionSpec,
                           IJBITTREAMSTATE *pStream,
                           IJENCODESTATE *pEncodeState)
{
    int  nMCUWidth;
    int  nMCUHeight;
    int  nImageMCUStep;
    int  nBlksInMCU;
    int  nMode;

    BOOL bMCUInterleaved;

    IJENPROCESSSPEC *pProcSpec;
    IJCOMPSPEC      *pCompSpec; 
    IJXRESULT       rtCode;

    pStream->nMarker=IJX_MARKER_NONE;
    pStream->nNumValidPrefetchedBits=0;
    pStream->nPrefetchedBits=0;

    pProcSpec   = &(pEncodeState->procSpec);
    pCompSpec   = (pEncodeState->compSpec);

    pEncodeState->nStatus=IJX_STATUS_START;

#ifdef IPPJPVER
    nJPEGCodeMode=(nJPEGCodeMode&(~IJX_MODE_PROGRESSIVE))|IJX_MODE_BASELINE;
#endif

    pEncodeState->nJPEGCodeMode=(nJPEGCodeMode&IJX_MODE_STILL_MASK);
    if (0==pEncodeState->nJPEGCodeMode) {
        pEncodeState->nJPEGCodeMode=IJX_MODE_BASELINE;
    }

    pEncodeState->nQuality=ijCalcQuantQualityFactor(nQuality);

    pEncodeState->imageSpec= *pImageSpec;

    if (pWaveSpec) {
        pEncodeState->waveSpec = *pWaveSpec;
    } else {
        pEncodeState->waveSpec.nCodeMode=IWP_CM_NONE;
    }

    if (pMotionSpec) {
        pEncodeState->motionSpec=*pMotionSpec;
        pEncodeState->nJPEGCodeMode|=pMotionSpec->nCodeMode;
    } else {
        pEncodeState->motionSpec.nCodeMode=IJX_MODE_MOTION_NONE;
    }
                           
    pImageSpec  = &(pEncodeState->imageSpec);
    pMotionSpec = &(pEncodeState->motionSpec);

    if (8!=pImageSpec->nPrecision) {
       return IJX_RTCODE_E_NOTSUPPORTEDPRECISION;
    }

    if (0<nResartInterval) {
        pEncodeState->nRstInterval=nResartInterval;
    } else {
        pEncodeState->nRstInterval=(0>nResartInterval)?128:0;
    }

    pEncodeState->nPrecision=pImageSpec->nPrecision;

    if (IIP_CM_GRAY==pImageSpec->nColorMode) {
        nMCUWidth=8;
        nMCUHeight=8;
        nImageMCUStep=8;
        nBlksInMCU=1;
        pEncodeState->imageSpec.nSamplingMode=IIP_SM_NONE;
        pEncodeState->imageSpec.nNumComponent=1;

        pProcSpec->funcAdjustMCUBuf=(PFUNCADJUSTMCUBUFFER)ijAdjustMCUBufferFwd_1;
        pProcSpec->funcCopyExpand=ijxCopyExpand_8u_C1;
        pProcSpec->funcMCUColorConvert=ijSub128_8x8_8u16s_C1;
        pProcSpec->funcMCUTransform=ijTransformFwd_MCU_16s_C1_I;

        pProcSpec->funcMotionDiffFirst=(PFUNCODEC)ijMotionDiffEncoder_MCU_First_16s_C1;
        pProcSpec->funcMotionDiffEncoder=(PFUNCODEC)ijMotionDiffEncoder_MCU_First_16s_C1;
        pProcSpec->funcMotionDiffRefine=(PFUNCODEC)ijMotionDiffEncoder_MCU_Refine_16s_C1;

        pProcSpec->funcHuffmanEncoder=(PFUNCHUFFMANCODER_BLS)ijHuffmanEncode_Gray_BLS;
        pProcSpec->funcHuffmanPDCEncoder=(PFUNCHUFFMANCODER_PDC)ijHuffmanEncode_Gray_DC;

#ifdef IPPJPVER
        pProcSpec->funcGetHuffmanDCFREQ=NULL;
        pProcSpec->funcGetHuffmanFREQ=NULL;
#else
        pProcSpec->funcGetHuffmanDCFREQ=(PFUNCGETHUFFMANFREQ_PDC)ijGetHuffmanFREQ_Gray_DC;
        pProcSpec->funcGetHuffmanFREQ=(PFUNCGETHUFFMANFREQ)ijGetHuffmanFREQ_Gray;
#endif
        ijInitComponentSpec(0,1,1, 0, 0, 0, pCompSpec);

    } else if ((IIP_CM_BGR555|IIP_CM_BGR565|IIP_CM_BGR)&pImageSpec->nColorMode) {

        pProcSpec->funcAdjustMCUBuf=(PFUNCADJUSTMCUBUFFER)ijAdjustMCUBufferFwd_3;

        switch (pImageSpec->nSamplingMode) {
            case IIP_SM_NONE:
                nMCUWidth=8;
                nMCUHeight=8;
                nBlksInMCU=3;
                pEncodeState->imageSpec.nNumComponent=3;
                if (IIP_CM_BGR&pImageSpec->nColorMode) {
                    nImageMCUStep=24;
                    pProcSpec->funcCopyExpand=ijxCopyExpand_8u_C3;
                    pProcSpec->funcMCUColorConvert=ippiBGRToYCbCr444LS_MCU_8u16s_C3P3;
                } else if (IIP_CM_BGR555&pImageSpec->nColorMode) {
#ifdef IPPJPVER
                    return IJX_RTCODE_E_NOTSUPPORTEDPARAM;
#else     
                    nImageMCUStep=16;
                    pProcSpec->funcCopyExpand=ijxCopyExpand_16u_C1;
                    pProcSpec->funcMCUColorConvert=(PFUNCCCFWD_MCU_8U16S)ippiBGR555ToYCbCr444LS_MCU_16u16s_C3P3;
#endif
                } else if (IIP_CM_BGR565&pImageSpec->nColorMode) {
#ifdef IPPJPVER
                    return IJX_RTCODE_E_NOTSUPPORTEDPARAM;
#else     
                    nImageMCUStep=16;
                    pProcSpec->funcCopyExpand=ijxCopyExpand_16u_C1;
                    pProcSpec->funcMCUColorConvert=(PFUNCCCFWD_MCU_8U16S)ippiBGR565ToYCbCr444LS_MCU_16u16s_C3P3;
#endif
                } else {
                    return IJX_RTCODE_ERROR;
                }
                pProcSpec->funcMCUTransform=ijTransformFwd444_MCU_16s_C3_I;

                pProcSpec->funcMotionDiffFirst=(PFUNCODEC)ijMotionDiffEncoder_MCU444_First_16s_C3;
                pProcSpec->funcMotionDiffEncoder=(PFUNCODEC)ijMotionDiffEncoder_MCU444_First_16s_C3;
                pProcSpec->funcMotionDiffRefine=(PFUNCODEC)ijMotionDiffEncoder_MCU444_Refine_16s_C3;

                pProcSpec->funcHuffmanEncoder=(PFUNCHUFFMANCODER_BLS)ijHuffmanEncode_444_BLS;
                pProcSpec->funcHuffmanPDCEncoder=(PFUNCHUFFMANCODER_PDC)ijHuffmanEncode_444_DC;
#ifdef IPPJPVER
                pProcSpec->funcGetHuffmanDCFREQ=NULL;
                pProcSpec->funcGetHuffmanFREQ=NULL;
#else
                pProcSpec->funcGetHuffmanDCFREQ=(PFUNCGETHUFFMANFREQ_PDC)ijGetHuffmanFREQ_444_DC;
                pProcSpec->funcGetHuffmanFREQ=(PFUNCGETHUFFMANFREQ)ijGetHuffmanFREQ_444;
#endif

                ijInitComponentSpec(0,1,1, 0, 0, 0, pCompSpec);
                ijInitComponentSpec(1,1,1, 1, 1, 1, pCompSpec);
                ijInitComponentSpec(2,1,1, 1, 1, 1, pCompSpec);
                break;
            case IIP_SM_422:
                nMCUWidth=16;
                nMCUHeight=8;
                nBlksInMCU=4;
                pEncodeState->imageSpec.nNumComponent=3;
                if (IIP_CM_BGR&pImageSpec->nColorMode) {
                    nImageMCUStep=48;
                    pProcSpec->funcCopyExpand=ijxCopyExpand_8u_C3;
                    pProcSpec->funcMCUColorConvert=ippiBGRToYCbCr422LS_MCU_8u16s_C3P3;
                } else if (IIP_CM_BGR555&pImageSpec->nColorMode) {
#ifdef IPPJPVER
                    return IJX_RTCODE_E_NOTSUPPORTEDPARAM;
#else     
                    nImageMCUStep=32;
                    pProcSpec->funcCopyExpand=ijxCopyExpand_16u_C1;
                    pProcSpec->funcMCUColorConvert=(PFUNCCCFWD_MCU_8U16S)ippiBGR555ToYCbCr422LS_MCU_16u16s_C3P3;
#endif
                } else if (IIP_CM_BGR565&pImageSpec->nColorMode) {
#ifdef IPPJPVER
                    return IJX_RTCODE_E_NOTSUPPORTEDPARAM;
#else     

                    nImageMCUStep=32;
                    pProcSpec->funcCopyExpand=ijxCopyExpand_16u_C1;
                    pProcSpec->funcMCUColorConvert=(PFUNCCCFWD_MCU_8U16S)ippiBGR565ToYCbCr422LS_MCU_16u16s_C3P3;
#endif
                } else {
                    return IJX_RTCODE_ERROR;
                }
                pProcSpec->funcMCUTransform=ijTransformFwd422_MCU_16s_C3_I;

                pProcSpec->funcMotionDiffFirst=(PFUNCODEC)ijMotionDiffEncoder_MCU422_First_16s_C3;
                pProcSpec->funcMotionDiffEncoder=(PFUNCODEC)ijMotionDiffEncoder_MCU422_First_16s_C3;
                pProcSpec->funcMotionDiffRefine=(PFUNCODEC)ijMotionDiffEncoder_MCU422_Refine_16s_C3;

                pProcSpec->funcHuffmanEncoder=(PFUNCHUFFMANCODER_BLS)ijHuffmanEncode_422_BLS;
                pProcSpec->funcHuffmanPDCEncoder=(PFUNCHUFFMANCODER_PDC)ijHuffmanEncode_422_DC;
#ifdef IPPJPVER
                pProcSpec->funcGetHuffmanDCFREQ=NULL;
                pProcSpec->funcGetHuffmanFREQ=NULL;
#else
                pProcSpec->funcGetHuffmanDCFREQ=(PFUNCGETHUFFMANFREQ_PDC)ijGetHuffmanFREQ_422_DC;
                pProcSpec->funcGetHuffmanFREQ=(PFUNCGETHUFFMANFREQ)ijGetHuffmanFREQ_422;
#endif


                ijInitComponentSpec(0,2,1, 0, 0, 0,pCompSpec);
                ijInitComponentSpec(1,1,1, 1, 1, 1,pCompSpec);
                ijInitComponentSpec(2,1,1, 1, 1, 1,pCompSpec);
                break;
            case  IIP_SM_411:
                nMCUWidth=16;
                nMCUHeight=16;
                nImageMCUStep=48;
                nBlksInMCU=6;
                pEncodeState->imageSpec.nNumComponent=3;
                if (IIP_CM_BGR&pImageSpec->nColorMode) {
                    nImageMCUStep=48;
                    pProcSpec->funcCopyExpand=ijxCopyExpand_8u_C3;
                    pProcSpec->funcMCUColorConvert=ippiBGRToYCbCr411LS_MCU_8u16s_C3P3;
                } else if (IIP_CM_BGR555&pImageSpec->nColorMode) {
#ifdef IPPJPVER
                    return IJX_RTCODE_E_NOTSUPPORTEDPARAM;
#else     

                    nImageMCUStep=32;
                    pProcSpec->funcCopyExpand=ijxCopyExpand_16u_C1;
                    pProcSpec->funcMCUColorConvert=(PFUNCCCFWD_MCU_8U16S)ippiBGR555ToYCbCr411LS_MCU_16u16s_C3P3;
#endif
                } else if (IIP_CM_BGR565&pImageSpec->nColorMode) {
#ifdef IPPJPVER
                    return IJX_RTCODE_E_NOTSUPPORTEDPARAM;
#else     

                    nImageMCUStep=32;
                    pProcSpec->funcCopyExpand=ijxCopyExpand_16u_C1;
                    pProcSpec->funcMCUColorConvert=(PFUNCCCFWD_MCU_8U16S)ippiBGR565ToYCbCr411LS_MCU_16u16s_C3P3;
#endif
                } else {
                    return IJX_RTCODE_ERROR;
                }
                pProcSpec->funcMCUTransform=ijTransformFwd411_MCU_16s_C3_I;

                pProcSpec->funcMotionDiffFirst=(PFUNCODEC)ijMotionDiffEncoder_MCU411_First_16s_C3;
                pProcSpec->funcMotionDiffEncoder=(PFUNCODEC)ijMotionDiffEncoder_MCU411_First_16s_C3;
                pProcSpec->funcMotionDiffRefine=(PFUNCODEC)ijMotionDiffEncoder_MCU411_Refine_16s_C3;

                pProcSpec->funcHuffmanEncoder=(PFUNCHUFFMANCODER_BLS)ijHuffmanEncode_411_BLS;
                pProcSpec->funcHuffmanPDCEncoder=(PFUNCHUFFMANCODER_PDC)ijHuffmanEncode_411_DC;
#ifdef IPPJPVER
                pProcSpec->funcGetHuffmanDCFREQ=NULL;
                pProcSpec->funcGetHuffmanFREQ=NULL;
#else
                pProcSpec->funcGetHuffmanDCFREQ=(PFUNCGETHUFFMANFREQ_PDC)ijGetHuffmanFREQ_411_DC;
                pProcSpec->funcGetHuffmanFREQ=(PFUNCGETHUFFMANFREQ)ijGetHuffmanFREQ_411;
#endif

                ijInitComponentSpec(0,2,2, 0, 0, 0, pCompSpec);
                ijInitComponentSpec(1,1,1, 1, 1, 1, pCompSpec);
                ijInitComponentSpec(2,1,1, 1, 1, 1, pCompSpec);
                break;
            default:
                return IJX_RTCODE_E_NOTSUPPORTEDPARAM;
        }
    }
    else {
        return IJX_RTCODE_E_NOTSUPPORTEDPARAM;
    }


    switch (nJPEGCodeMode) {
        case IJX_MODE_BASELINE:
        case (IJX_MODE_BASELINE|IJX_MODE_MOTION_INDIV):
            nMode=IJX_MODE_BASELINE;
            bMCUInterleaved=TRUE;
            pProcSpec->funcCompress=(PFUNCODEC)ijCompress_BaseLine_L;
            break;
        case (IJX_MODE_BASELINE|IJX_MODE_MOTION_DIFF):
        case (IJX_MODE_BASELINE|IJX_MODE_MOTION_BRIEF):
            nMode=IJX_MODE_BASELINE;
            bMCUInterleaved=FALSE;
            pProcSpec->funcCompress=(PFUNCODEC)ijCompress_BaseLine_L;
            break;

///////////////////////////////////////
#ifdef _BASELINE_A
        case IJX_MODE_BASELINE_A:
        case (IJX_MODE_BASELINE_A|IJX_MODE_MOTION_INDIV):
        case (IJX_MODE_BASELINE_A|IJX_MODE_MOTION_DIFF):
        case (IJX_MODE_BASELINE_A|IJX_MODE_MOTION_BRIEF):
            nMode=IJX_MODE_BASELINE_A;
            bMCUInterleaved=FALSE;
            pProcSpec->funcCompress=(PFUNCODEC)ijCompress_BaseLine_H;
            break;
#endif
///////////////////////////////////////

        case IJX_MODE_PROGRESSIVE:
        case (IJX_MODE_PROGRESSIVE|IJX_MODE_MOTION_INDIV):
        case (IJX_MODE_PROGRESSIVE|IJX_MODE_MOTION_DIFF):
        case (IJX_MODE_PROGRESSIVE|IJX_MODE_MOTION_BRIEF):
            nMode=IJX_MODE_PROGRESSIVE;
            bMCUInterleaved=FALSE;
#ifdef IPPJPVER
            pProcSpec->funcCompress=NULL;
#else 
            pProcSpec->funcCompress=(PFUNCODEC)ijCompress_Progressive;
#endif
            break;

        /* If not logo frame */
        case (IJX_MODE_MOTION_INDIV):
            nMode=IJX_MODE_BASELINE;
            bMCUInterleaved=TRUE;
            pProcSpec->funcCompress=(PFUNCODEC)ijCompress_Motion_Indiv;
            break;

///////////////////////////////////////
#ifdef _MOTION_DIFF
        case (IJX_MODE_MOTION_DIFF):
            nMode=IJX_MODE_BASELINE;
            bMCUInterleaved=FALSE;
            pProcSpec->funcCompress=(PFUNCODEC)ijCompress_Motion_Diff;
            break;
#endif
///////////////////////////////////////

///////////////////////////////////////
#ifdef _MOTION_BRIEF
        case (IJX_MODE_MOTION_BRIEF):
            nMode=IJX_MODE_BASELINE;
            bMCUInterleaved=FALSE;
            pProcSpec->funcCompress=(PFUNCODEC)ijCompress_Motion_Brief;
            break;
#endif
///////////////////////////////////////
        default:
            return IJX_RTCODE_E_NOTSUPPORTEDPARAM;
    }

    ijInitMCU(pImageSpec->nWidth, pImageSpec->nHeight, 
              nMCUWidth, nMCUHeight, nImageMCUStep, nBlksInMCU, 
              pImageSpec->nSamplingMode, bMCUInterleaved,
              &(pEncodeState->mcuSpec));

    
    pEncodeState->nHMCUCurPos=0;
    pEncodeState->nVMCUCurPos=0;
//    pEncodeState->counter.nFrameMCUCounter=0;
//    pEncodeState->counter.nScanMCUCounter=0;
    pEncodeState->counter.nScanCounter=0;
    pEncodeState->counter.nFrameScanCounter=0;
//    pEncodeState->counter.nTotalMCUCounter=0;
//    pEncodeState->counter.nTotalScanCounter=0;
    pEncodeState->counter.nTotalFrameCounter=0;
    pEncodeState->counter.nProcessedBitsLen=0;

    pEncodeState->paIdxDCTQuantTable[0]=&(pEncodeState->dctQuantTable[0]);
    pEncodeState->paIdxDCTDequantTable[0]=&(pEncodeState->dctDequantTable[0]);
    pEncodeState->paIdxDCHuffTable[0]=&(pEncodeState->dcHuffTable[0]);
    pEncodeState->paIdxACHuffTable[0]=&(pEncodeState->acHuffTable[0]);

    if (3==pEncodeState->imageSpec.nNumComponent) {
        pEncodeState->paIdxDCTQuantTable[1]=&(pEncodeState->dctQuantTable[64]);
        pEncodeState->paIdxDCTQuantTable[2]=&(pEncodeState->dctQuantTable[64]);
        if (IJX_MODE_MOTION_MASK&nJPEGCodeMode) {
            pEncodeState->paIdxDCTDequantTable[1]=&(pEncodeState->dctDequantTable[64]);
            pEncodeState->paIdxDCTDequantTable[2]=&(pEncodeState->dctDequantTable[64]);
        }
        pEncodeState->paIdxDCHuffTable[1]=&(pEncodeState->dcHuffTable[1]);
        pEncodeState->paIdxDCHuffTable[2]=&(pEncodeState->dcHuffTable[1]);
        pEncodeState->paIdxACHuffTable[1]=&(pEncodeState->acHuffTable[1]);
        pEncodeState->paIdxACHuffTable[2]=&(pEncodeState->acHuffTable[1]);
    } else if (4==pEncodeState->imageSpec.nNumComponent) {
        pEncodeState->paIdxDCTQuantTable[1]=&(pEncodeState->dctQuantTable[64]);
        pEncodeState->paIdxDCTQuantTable[2]=&(pEncodeState->dctQuantTable[64]);
        pEncodeState->paIdxDCTQuantTable[3]=&(pEncodeState->dctQuantTable[0]);
        if (IJX_MODE_MOTION_MASK&nJPEGCodeMode) {
            pEncodeState->paIdxDCTDequantTable[1]=&(pEncodeState->dctDequantTable[64]);
            pEncodeState->paIdxDCTDequantTable[2]=&(pEncodeState->dctDequantTable[64]);
            pEncodeState->paIdxDCTDequantTable[3]=&(pEncodeState->dctDequantTable[0]);
        }
        pEncodeState->paIdxDCHuffTable[1]=&(pEncodeState->dcHuffTable[1]);
        pEncodeState->paIdxDCHuffTable[2]=&(pEncodeState->dcHuffTable[1]);
        pEncodeState->paIdxDCHuffTable[3]=&(pEncodeState->dcHuffTable[0]);
        pEncodeState->paIdxACHuffTable[1]=&(pEncodeState->acHuffTable[1]);
        pEncodeState->paIdxACHuffTable[2]=&(pEncodeState->acHuffTable[1]);
        pEncodeState->paIdxACHuffTable[3]=&(pEncodeState->acHuffTable[0]);
    } else if (1!=pEncodeState->imageSpec.nNumComponent) {
        return IJX_RTCODE_E_NOTSUPPORTEDPARAM;
    }

    rtCode=ijCalcEncBufferSize(pEncodeState->nJPEGCodeMode,
                               &(pEncodeState->mcuSpec),
                               &(pEncodeState->bufSpec) );

    if (!IJX_SUCCEEDED(rtCode)){
        return rtCode;
    }

    // Write SOI, APP0 and COM 
    rtCode=ijWriteHead(NULL,0, pStream, pEncodeState);
    if (!IJX_SUCCEEDED(rtCode)){
        return rtCode;
    }

    // Build default Quant table;
    rtCode=ijBuildEncodeQuantTables(pEncodeState->imageSpec.nNumComponent,
                                    NULL, pStream, pEncodeState);
    if (!IJX_SUCCEEDED(rtCode)){
        return rtCode;
    }

    // Build default Huffman table;
    if (IJX_MODE_BASELINE & (pEncodeState->nJPEGCodeMode) ||
        IJX_MODE_MOTION_MASK   & (pEncodeState->nJPEGCodeMode) ) {
        rtCode=ijBuildScanHuffTables_BLS(pStream, pEncodeState);
        if (!IJX_SUCCEEDED(rtCode)){
            return rtCode;
        }
    }

    // Write First Frame marker
    rtCode=ijInitFrameSpecFwd(nMode, pEncodeState);
    if (!IJX_SUCCEEDED(rtCode)){
        return rtCode;
    }

    rtCode=ijWrite_SOF(&(pEncodeState->frameSpec),
                       pEncodeState->compSpec,
                       pStream);
    if (!IJX_SUCCEEDED(rtCode)){
        return rtCode;
    }


    pEncodeState->nStatus=IJX_STATUS_INIT;

    return IJX_RTCODE_OK;
}

/******************************************************************************
// Name:            ijxGetCompressBufLen
// Description:     Get internal buffer length for encoding
// Input Arguments:
//    pEncodeState: Points to IJENCODESTATE data structure.
// Output Arguments:
//        pnBufLen: Points to int type which contains desired buffer length when function return.
//                  
******************************************************************************/
IJXRESULT ijxGetCompBufLen (int *pnBufLen, 
                            IJENCODESTATE *pEncodeState)
{
    *pnBufLen=0;

    if (pnBufLen&&pEncodeState) {
        *pnBufLen=pEncodeState->bufSpec.nMaxBufLen;
        return IJX_RTCODE_OK;
    }
    return IJX_RTCODE_E_ERRPARAM;
}

/******************************************************************************
// Name:            ijxCompBufInit
// Description:     Init all internal buffers for encoding
// Input Arguments:
//         pBufPtr: Points to the buffer which allocated by codec caller.
//         nBufLen: Specifies internal buffer length
// Output Arguments:
//    pEncodeState: Identifies IJENCODESTATE strcuture.
//                     
******************************************************************************/
IJXRESULT ijxCompBufInit(void *pBufPtr, 
                        int  nBufLen,
                        IJENCODESTATE *pEncodeState)
{
    IJXRESULT rtCode;
    rtCode=ijInitBuffers( pBufPtr, nBufLen,
                         &(pEncodeState->bufSpec),
                         &(pEncodeState->mcuSpec),
                         &(pEncodeState->imageSpec) );
    return rtCode;
}

/******************************************************************************
// Name:            ijxCompress
// Description:     JPEG compress.
// Input Arguments:
//      ppImageBuf: Points to image buffer pointers.
//  pnImageBufStep: Points to array of image buffer step.
//         pStream: Identifies IJBITTREAMSTATE data structure.
//    pEncodeState: Identifies IJENCODESTATE strcuture.
//                          
// Returns:          
//        [Success] IJX_RTCODE_OK
//        [Failure] IJX_RTCODE_BAGARG
//                  IJX_RTCODE_INSUFFICIENTBUF
//                  IJX_RTCODE_NOTSUPPORTMARKER
//                  IJX_RTCODE_ERRPARSE
//                     
//                  
******************************************************************************/
IJXRESULT ijxCompress(void     **ppImageBuf,
                      int      *pnImageBufStep,  
                      IJBITTREAMSTATE *pStream,
                      IJENCODESTATE *pEncodeState)
{
    IJXRESULT rtCode;
    
    if (NULL==ppImageBuf||NULL==pnImageBufStep) {
        rtCode=ijWrite_Marker(IJX_MARKER_EOI, pStream);
        if (!IJX_SUCCEEDED(rtCode)){
            return rtCode;
        }
        if (0>=pEncodeState->counter.nTotalFrameCounter) {
            return IJX_RTCODE_ERROR;
        }
        return IJX_RTCODE_S_EOF;
    }

    pEncodeState->bufSpec.paImageBuf[0]=ppImageBuf[0];
    pEncodeState->bufSpec.paImageBufCur[0]=ppImageBuf[0];
    pEncodeState->bufSpec.naImageStep[0]=pnImageBufStep[0];

    rtCode=pEncodeState->procSpec.funcCompress(pStream, pEncodeState);
    if (!IJX_SUCCEEDED(rtCode)){
        return rtCode;
    }

    if (IJX_RTCODE_S_EOF==rtCode) {
        /* MCU Counter */
//        pEncodeState->counter.nFrameMCUCounter+=pEncodeState->counter.nScanMCUCounter;
//        pEncodeState->counter.nTotalMCUCounter+=pEncodeState->counter.nScanMCUCounter;

        /* Scan Counter */
        pEncodeState->counter.nFrameScanCounter=pEncodeState->counter.nScanCounter;
//        pEncodeState->counter.nTotalScanCounter+=pEncodeState->counter.nScanCounter;
    }

    return rtCode;
}

/******************************************************************************
// Name:            ijxAddWaveStream
// Description:     Add wave stream into main code stream.
// Input Arguments:
//  pWaveStreamBuf: Points to wave stream buffer.
//     nByteLength: Specifies wave buffer length in bytes.
// Output Arguments:
//         pStream: Identifies IJBITTREAMSTATE data structure.
//                     
//                  
******************************************************************************/
IJXRESULT ijxAddWaveStream(void *pWaveStreamBuf,
                           int  nByteLength,
                           IJBITTREAMSTATE *pStream)
{
    return ijAddWaveStream(pWaveStreamBuf, nByteLength,pStream);
}

/******************************************************************************
// Name:            ijxAddTimeStamp
// Description:     Add time stamp into main code stream
// Input Arguments:
//       pTimeSpec: Points to IJTIMESPEC data structure.
// Output Arguments:
//         pStream: Identifies IJBITTREAMSTATE data structure.
// Returns:          
//                     
//                  
******************************************************************************/
IJXRESULT ijxAddTimeStamp(IJTIMESPEC     *pTimeSpec,
                          IJBITTREAMSTATE *pStream)
{
    return ijAddTimeStamp(pTimeSpec, pStream);    
}

/******************************************************************************
// Name:            ijxIsInMotionEncoding
// Description:     Used to Check if the current status is in Motion coding.
// Input Arguments:
//    pEncodeState: Identifies IJENCODESTATE strcuture.
// Output Arguments:
// Returns:          
//                     
//                  
******************************************************************************/
IJXRESULT ijxIsInMotionEncoding(IJENCODESTATE *pEncodeState)
{
    if (IJX_MODE_STILL_MASK&pEncodeState->nJPEGCodeMode){
        return IJX_RTCODE_NO;
    }
    return IJX_RTCODE_OK;
}

/* EOF */

